#!  /usr/bin/env python
#
# Good robot using irc.bot.
#
# Joel Rosdahl <joel@rosdahl.net>
"""A good robot.

This is a robot that uses the SingleServerIRCBot class from
irc.bot.  The bot enters a channel and listens for commands in
private messages and channel traffic.  Commands in channel messages
are given by prefixing the text by the bot name followed by a colon.
It also responds to DCC CHAT invitations and echos data sent in such
sessions.

The known commands are:

    fortune -- Sends a random fortune cookie.

    stats -- Prints some channel information.

    disconnect -- Disconnect the bot.  The bot will try to reconnect
                  after 60 seconds.

    die -- Let the bot cease to exist.

    dcc -- Let the bot invite you to a DCC CHAT connection.
"""

import random
import irc.bot
import irc.strings
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr

from lxml import html
import requests

class TestBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, port=6667):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
        self.channel = channel
        self.kicklist = ["your mom", "kick me"]
        self.hello = ["hello", "hi"]

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        c.join(self.channel)

    def on_privmsg(self, c, e):
        self.do_command(e, e.arguments[0])

    def on_pubmsg(self, c, e):
        for kick_phrase in self.kicklist:
            if e.arguments[0].find(kick_phrase) > -1:
                self.kick(e, e.source.nick)
                return
        for greeting in self.hello:
            if e.arguments[0] == greeting:
                self.greet(e)
                return
        a = e.arguments[0].split(":", 1)

        if len(a) > 1:
            if irc.strings.lower(a[0]) == irc.strings.lower(self.connection.get_nickname()):
                self.do_command(e, a[1].strip())
            else:
                link = self.get_yt_link(e, a[1])
                if link != "":
                    self.preview_video(e, link)

    def on_dccmsg(self, c, e):
        # non-chat DCC messages are raw bytes; decode as text
        text = e.arguments[0].decode('utf-8')
        c.privmsg("You said: " + text)

    def on_dccchat(self, c, e):
        if len(e.arguments) != 2:
            return
        args = e.arguments[1].split()
        if len(args) == 4:
            try:
                address = ip_numstr_to_quad(args[2])
                port = int(args[3])
            except ValueError:
                return
            self.dcc_connect(address, port)

    def reply(self, e, msg):
        c = self.connection
        if e.type == "privmsg":
            c.privmsg(e.source.nick, msg)
        else:
            c.privmsg(e.target, msg)

    def do_command(self, e, cmd):
        nick = e.source.nick
        c = self.connection
        link = self.get_yt_link(e, cmd)

        if link != "":
            self.preview_video(e, link)
        elif cmd == "disconnect":
            self.disconnect()
        elif cmd == "die":
            self.die()
        elif cmd == "fortune":
            self.fortune(e)
        elif cmd.startswith("topic"):
            self.topic(e, cmd.split(' ', 1)[1])
        elif cmd.startswith("kick"):
            self.kick(e, cmd.split(' ', 1)[1])
        elif cmd.startswith("insult"):
            self.reply(e, self.insult(cmd.split(' ', 1)[1]))
        elif cmd == "stats":
            self.stats(e)
        elif cmd == "dcc":
            dcc = self.dcc_listen()
            c.ctcp("DCC", nick, "CHAT chat %s %d" % (ip_quad_to_numstr(dcc.localaddress), dcc.localport))
        else:
            c.notice(nick, "oh noes how this get here i not good with computer")

    def get_yt_link(self, e, vid):
        for findStr in ["youtube.com/watch?v=", "youtu.be/"]:
            findIX = vid.lower().find(findStr)
            if findIX != -1:
                return "https://" + vid[findIX : findIX + len(findStr) + 11]
        return ""

    def preview_video(self, e, link):
        page = requests.get(link)
        youtube = html.fromstring(page.content)
        video_title = youtube.xpath(" //span[@id='eow-title']/@title ")[0]
        self.reply(e, "Video Title: " + video_title)

    def stats(self, e):
        c = self.connection
        nick = e.source.nick
        for chname, chobj in self.channels.items():
            if chname == e.target:
                c.notice(nick, "--- Channel statistics ---")
                c.notice(nick, "Channel: " + chname)
                users = sorted(chobj.users())
                c.notice(nick, "Users: " + ", ".join(users))
                opers = sorted(chobj.opers())
                c.notice(nick, "Opers: " + ", ".join(opers))
                voiced = sorted(chobj.voiced())
                c.notice(nick, "Voiced: " + ", ".join(voiced))

    def fortune(self, e):
        if e.type == "privmsg":
            fortune = "Your fortune: "
        else:
            fortune = e.source.nick + "'s fortune: "
        cookie = random.randint(0, 10)
        if cookie == 0:
            fortune += 'Godly Luck'
        elif cookie == 1:
            fortune += 'You will meet a dark handsome stranger'
        elif cookie == 2:
            fortune += 'Bad Luck'
        elif cookie == 3:
            fortune += 'kita------(`V`)------!!!!'
        elif cookie == 4:
            fortune +=  'Good news will come to you by mail'
        elif cookie == 5:
            fortune +=  'Average Luck'
        elif cookie == 6:
            fortune += '( `_>`) fuun '
        elif cookie == 7:
            fortune +=  'Very Bad Luck'
        elif cookie == 8:
            fortune += 'Better not tell you now'
        elif cookie == 9:
            fortune += 'Excellent Luck'
        elif cookie == 10:
            fortune += 'Reply hazy, try again'
        self.reply(e, fortune)

    def topic(self, e, topic):
        c = self.connection
        if self.hasOP(e):
            c.topic(e.target, topic)
        else:
            c.notice(e.source.nick, "Can't set topic: " + topic)

    def greet(self, e):
        greeting = "Hi, %s!" % e.source.nick
        self.reply(e, greeting)

    def hasOP(self, e):
        for chname, chobj in self.channels.items():
            if chname == e.target and self.connection.get_nickname() in chobj.opers():
                return True
        return False

    def kick(self, e, who):
        if self.hasOP(e):
            self.connection.kick(e.target, who, self.insult(who))
        else:
            self.reply(e, self.insult(who))

    def insult(self, who):
        which = random.randint(1, 7)
        if which == 1:
            insult = who + ", I know a few lakes around, and I have a pair of cement boots with your name on them"
        elif which == 2:
            insult = who + ", why do I keep letting you in?"
        elif which == 3:
            insult = "not you again, " + who
        elif which == 4:
            insult = "memo to self: ban " + who
        elif which == 5:
            insult = "what in the world could... oh, it's just " + who
        elif which == 6:
            insult = who + ", go home"
        elif which == 7:
            insult = "who can tell me one thing that isn't wrong with " + who
        return insult

def main():
    import sys
    import ptvsd
    if len(sys.argv) < 4 or len(sys.argv) > 5:
        print("Usage: robot.py <server[:port]> <channel> <nickname> [debugkey]")
        sys.exit(1)

    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print("Error: Erroneous port.")
            sys.exit(1)
    else:
        port = 6667
    channel = sys.argv[2]
    nickname = sys.argv[3]
    if len(sys.argv) == 5:
        ptvsd.enable_attach(sys.argv[4])

    bot = TestBot(channel, nickname, server, port)
    bot.start()

if __name__ == "__main__":
    main()
